using MultiAgentsServer.Scripts.Shared;
using MultiAgentsServer.Scripts.ToolSets;
using MultiAgentsShared;
using OpenAI.ObjectModels.RequestModels;
using System.Text.Json;

namespace MultiAgentsServer.Scripts.Services;

#pragma warning disable CS8604
public class FunctionCallerService
{
    //private static ChatRoomComProtocolService chatRoomComProtocolService;

    public FunctionCallerService()
    {
        //chatRoomComProtocolService = chatRoomComProtocolServiceIn;
    }

    public static string? ToolInvoker(List<ToolCall> toolCalls)
    {
        if (toolCalls == null)
        {
            return null;
        }

        try
        {
            var finalMsg = "";
            foreach (ToolCall toolCall in toolCalls)
            {
                FunctionCall? funcCall = toolCall.FunctionCall;
                string funcName = funcCall?.Name ?? throw Debug.ShouldNotHappen();
                List<Dictionary<string, object>> funcParams = funcCall.ParseArgumentsAdvanced();

                foreach (var param in funcParams)
                {
                    var funcCallResult = "";
                    var argumentsDisp = "";
                    switch (funcCall.Name)
                    {
                        //case "VoteForChatRoomCompletion":
                        //    argumentsDisp += param["agent"].ToString();
                        //    argumentsDisp += ", \n";
                        //    argumentsDisp += param["voteForCompletion"].ToString();

                        //    var agentEnum = (ChatAgentEnum)Enum.Parse(typeof(ChatAgentEnum), param["agent"].ToString());

                        //    funcCallResult = chatRoomComProtocolService.VoteForChatRoomCompletion(agentEnum, bool.Parse(param["voteForCompletion"].ToString()));
                        //    break;
                        case "CheckFileExistInWorkspace":
                            argumentsDisp += param["relativeFilePath"].ToString();
                            funcCallResult = WorkspaceOperationToolsProvider.CheckFileExistInWorkspace(Convert.ToString(param["relativeFilePath"])).ToString();
                            break;
                        case "LoadFileFromWorkspace":
                            argumentsDisp += param["relativeFilePath"].ToString();
                            funcCallResult = WorkspaceOperationToolsProvider.LoadFileFromWorkspace(Convert.ToString(param["relativeFilePath"]));
                            break;
                        case "CreateFileInWorkspace":
                            argumentsDisp += param["relativeFilePath"].ToString();
                            argumentsDisp += ", \n";
                            argumentsDisp += param["fileContent"].ToString();
                            funcCallResult = WorkspaceOperationToolsProvider.CreateFileInWorkspace(Convert.ToString(param["relativeFilePath"]), Convert.ToString(param["fileContent"]) ?? "");
                            break;
                        case "ExploreWorkspaceDirectory":
                            funcCallResult = WorkspaceOperationToolsProvider.ExploreWorkspaceDirectory();
                            break;
                        default:
                            var errMsg = $"Function {funcName} not found";
                            Debug.LogError(errMsg);
                            return errMsg;
                    }

                    finalMsg += $"Made function call to {funcName} with: \n" +
                        $"({argumentsDisp}). \n\n" +
                        $"And result of this function call is {funcCallResult}\n";
                }
            }

            return finalMsg;
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }
}

public static class FunctionCallExtension
{
    public static List<Dictionary<string, object>> ParseArgumentsAdvanced(this FunctionCall funcCall)
    {
        List<string> argBlocks = ExtractBlocks(funcCall.Arguments ?? throw Debug.ShouldNotHappen());

        var finalArgs = new List<Dictionary<string, object>>();
        foreach (string argBlock in argBlocks)
        {
            finalArgs.Add([]);

            foreach (var param in ParseArguments(argBlock))
            {
                finalArgs.Last().Add(param.Key, param.Value);
            }
        }

        return finalArgs;
    }

    private static Dictionary<string, object> ParseArguments(string rawArgsStr)
    {
        var result = !string.IsNullOrWhiteSpace(rawArgsStr) ? JsonSerializer.Deserialize<Dictionary<string, object>>(rawArgsStr) : null;
        return result ?? [];
    }

    private static List<string> ExtractBlocks(string input)
    {
        List<string> blocks = [];
        int braceCount = 0;
        int start = 0;

        for (int i = 0; i < input.Length; i++)
        {
            if (input[i] == '{')
            {
                if (braceCount == 0)
                {
                    start = i; // Mark the start of a new block
                }
                braceCount++; // Increment count for each opening brace
            }
            else if (input[i] == '}')
            {
                braceCount--; // Decrement count for each closing brace
                if (braceCount == 0)
                {
                    // End of a block
                    blocks.Add(input.Substring(start, i - start + 1));
                }
            }
        }

        return blocks;
    }
}
